package io.github.talelin.latticy.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import io.github.talelin.autoconfigure.exception.NotFoundException;
import io.github.talelin.latticy.common.LocalUser;
import io.github.talelin.latticy.common.mybatis.Page;
import io.github.talelin.latticy.dto.userware.CreateUserwareDTO;
import io.github.talelin.latticy.dto.userware.UpdateUserwareDTO;
import io.github.talelin.latticy.model.UserDO;
import io.github.talelin.latticy.model.UserwareDO;
import io.github.talelin.latticy.mapper.UserwareMapper;
import io.github.talelin.latticy.model.WarehouseDO;
import io.github.talelin.latticy.service.GroupService;
import io.github.talelin.latticy.service.UserService;
import io.github.talelin.latticy.service.UserwareService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.github.talelin.latticy.service.WarehouseService;
import io.github.talelin.latticy.vo.WarehouseVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author generator@wulongbo
 * @since 2022-05-12
 */
@Service
public class UserwareServiceImpl extends ServiceImpl<UserwareMapper, UserwareDO> implements UserwareService {

    @Autowired
    private WarehouseService warehouseService;

    @Autowired
    private UserService userService;

    @Autowired
    private GroupService groupService;

    @Override
    public boolean createUserware(CreateUserwareDTO dto) {
        Integer userId = dto.getUserId();
        throwUserNotExistById(userId);
        List<String> wareCodes = dto.getCodes();
        int count = warehouseService.getWarehouseCountByWareCodes(wareCodes);
        if (count != wareCodes.size()) {
            throw new NotFoundException(18303);
        }
        QueryWrapper<UserwareDO> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UserwareDO::getUserId, userId).in(UserwareDO::getCode, wareCodes);
        List<UserwareDO> queryList = this.baseMapper.selectList(wrapper);
        // jdk1.8 没有 ifPresentOrElse
        if (queryList == null) {
            List<UserwareDO> list = wareCodes.parallelStream().map(code -> new UserwareDO(userId, code)).collect(Collectors.toList());
            return this.saveBatch(list);
        }
        List<String> oldCodes = queryList.parallelStream().map(UserwareDO::getCode).collect(Collectors.toList());
        List<String> newCodes = wareCodes.parallelStream().filter(s -> !oldCodes.contains(s)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(newCodes)) {
            throw new NotFoundException(18304);
        }
        List<UserwareDO> list = newCodes.parallelStream().map(code -> new UserwareDO(userId, code)).collect(Collectors.toList());
        return this.saveBatch(list);
    }

    @Override
    public List<WarehouseVO> getWareNameListByUserId(Integer userId) {
        return this.baseMapper.getWareNameListByUserId(userId);
    }

    @Override
    public List<String> getWareCodeListByUserId() {
        UserDO userDO = LocalUser.getLocalUser();
        boolean admin = groupService.checkIsRootByUserId(userDO.getId());
        if (admin) {
            return this.baseMapper.getWareCodeListByRoot();
        }
        return this.baseMapper.getWareCodeListByUserId(userDO.getId());
    }

    @Override
    public List<WarehouseVO> getWareNameList() {
        UserDO userDO = LocalUser.getLocalUser();
        boolean admin = groupService.checkIsRootByUserId(userDO.getId());
        if (admin) {
            return this.baseMapper.getWareNameList();
        }
        return this.getWareNameListByUserId(userDO.getId());
    }

    @Transactional
    @Override
    public boolean updateUserware(UpdateUserwareDTO dto) {
        Integer userId = dto.getUserId();
        List<String> codes = dto.getCodes();
        throwUserNotExistById(userId);
        if (CollectionUtils.isEmpty(codes)) {
            QueryWrapper<UserwareDO> wrapper = new QueryWrapper<>();
            wrapper.lambda().eq(UserwareDO::getUserId, userId);
            return this.baseMapper.delete(wrapper) > 0;
        }
        QueryWrapper<UserwareDO> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UserwareDO::getUserId, userId);
        List<UserwareDO> oldList = this.baseMapper.selectList(wrapper);
        List<String> oldCodes = oldList.parallelStream().map(UserwareDO::getCode).collect(Collectors.toList());
        List<String> removeCodes = oldCodes.parallelStream().filter(code -> !codes.contains(code)).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(removeCodes)) {
            this.baseMapper.deleteRealByUserIdAndCodes(userId, removeCodes);
        }
        List<String> addCodes = codes.parallelStream().filter(code -> !oldCodes.contains(code)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(addCodes)) {
            return true;
        }
        int count = warehouseService.getWarehouseCountByWareCodes(addCodes);
        if (count != addCodes.size()) {
            throw new NotFoundException(18303);
        }
        List<UserwareDO> addList = addCodes.stream().map(code -> new UserwareDO(userId, code)).collect(Collectors.toList());
        return this.saveBatch(addList);
    }

    private void throwUserNotExistById(Integer id) {
        boolean exist = userService.checkUserExistById(id);
        if (!exist) {
            throw new NotFoundException(10021);
        }
    }
}
